package com.github.rxyor.common.util.security;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import java.util.Date;
import org.jasypt.util.text.BasicTextEncryptor;

/**
 *<p>
 *签名与校验工具
 *</p>
 *
 * @author liuyang
 * @date 2019/4/9 Tue 14:45:00
 * @since 1.0.0
 */
@SuppressWarnings("all")
public class SafeSignVerifyUtil {

    /**
     * 默认有效时长
     */
    private final static Long DEFAULT_EXPIRE = 60L;

    /**
     * JWT 用户名key
     */
    private final static String USERNAME_KEY = "username";

    /**
     * jwt加密用户名
     */
    private String username;

    /**
     * 密码
     */
    private String password;

    /**
     * 失效时间
     */
    private Long expire;

    private SafeSignVerifyUtil() {
    }

    private SafeSignVerifyUtil(String username, String password, Long expire) {
        this.username = username;
        this.password = password;
        this.expire = expire;
    }

    public static Builder builder() {
        return new Builder();
    }

    /**
     * Jasypt 工具类加密（每次加密可以生成一个不同的密码）
     *
     * @param secret 密钥
     * @param content  明文
     * @return 加密后内容
     */
    private String encryptByPBEWithMD5AndDES(String secret, String content) {
        BasicTextEncryptor encryptor = new BasicTextEncryptor();
        encryptor.setPassword(secret);
        return encryptor.encrypt(content);
    }

    /**
     * Jasypt 工具类解密（每次加密可以生成一个不同的密码）
     *
     * @param secret 密钥
     * @param content  密文
     * @return 解密后内容
     */
    private String decryptByPBEWithMD5AndDES(String secret, String content) {
        BasicTextEncryptor encryptor = new BasicTextEncryptor();
        encryptor.setPassword(secret);
        return encryptor.decrypt(content);
    }

    /**
     * JWT 加密
     *
     * @param username 用户名
     * @param secret 密钥
     * @param expire 有效时长
     * @return 密文
     */
    private String encryptByJwtHMAC256(String username, String secret, Long expire) {
        try {
            Long expireMills = ((expire == null || expire <= 0) ? DEFAULT_EXPIRE : expire) * 1000;
            Date date = new Date(System.currentTimeMillis() + expireMills);
            Algorithm algorithm = Algorithm.HMAC256(secret);
            return JWT.create()
                .withClaim(USERNAME_KEY, username)
                .withExpiresAt(date)
                .sign(algorithm);
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * JWT 验证
     *
     * @param token 密文
     * @param username 用户名
     * @param secret 密钥
     * @return 验证结果
     */
    private Boolean verifyByJwtHMAC256(String token, String username, String secret) {
        try {
            Algorithm algorithm = Algorithm.HMAC256(secret);
            JWTVerifier verifier = JWT.require(algorithm)
                .withClaim(USERNAME_KEY, username)
                .build();
            verifier.verify(token);
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 生成一个JWT token
     *
     * @param username 用户名
     * @param secret 密钥
     * @param expire 有效时长
     * @return 密文
     */
    private String genJwtToken(String username, String secret, Long expire) {
        return encryptByJwtHMAC256(username, secret, expire);
    }

    private String genJasyptSecret(String secret) {
        return encryptByPBEWithMD5AndDES(this.password, secret);
    }

    private String deJayptSecret(String secret) {
        return decryptByPBEWithMD5AndDES(this.password, secret);
    }

    /**
     * 生成一个签名
     *
     * @param username 用户名
     * @param secret 密钥
     * @param expire 有效时长
     * @return 密文
     */
    private String sign(String username, String secret, Long expire) {
        String token = genJwtToken(username, secret, expire);
        //再次加密，得到一个动态的token
        return genJasyptSecret(token);
    }

    /**
     * 验证签名
     *
     * @param token 签名
     * @param username 用户名
     * @param secret 密钥
     * @return 密文
     */
    private Boolean verify(String token, String username, String secret) {
        String jwtToken = deJayptSecret(token);
        return verifyByJwtHMAC256(jwtToken, username, secret);
    }

    public String sign() {
        return sign(this.username, this.password, this.expire);
    }

    public Boolean verify(String token) {
        return verify(token, this.username, this.password);
    }


    public static class Builder {

        private String username = "JXU5NjQ4JXU2MEEw";

        private String password = "JXU1MjE4JXU5NjMz";

        private Long expire = DEFAULT_EXPIRE;

        public Builder() {
        }

        public Builder username(String username) {
            this.username = username;
            return this;
        }

        public Builder password(String password) {
            this.password = password;
            return this;
        }

        public Builder expire(Long expire) {
            this.expire = expire;
            return this;
        }

        public SafeSignVerifyUtil build() {
            return new SafeSignVerifyUtil(this.username, this.password, expire);
        }

    }


}
